import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_base/config/app_color.dart';
import 'package:flutter_base/utils/log/utils_log.dart';

import '../controller/base_controller.dart';
import '../mixin/base_loading_mixin.dart';

class BaseGetBuilder<T extends BaseController> extends StatelessWidget
    with BaseLoadingMixin {
  final GetControllerBuilder<T>? builder;
  final bool global;
  final Object? id;
  final String? tag;
  final bool autoRemove;
  final bool assignId;
  final Object Function(T value)? filter;
  final void Function(GetBuilderState<T> state)? initState,
      dispose,
      didChangeDependencies;
  final void Function(GetBuilder oldWidget, GetBuilderState<T> state)?
      didUpdateWidget;
  final T? init;
  final Positioned? backgroundView;
  final PreferredSizeWidget? appBar;
  final Color? backgroundColor;
  final bool extendBodyBehindAppBar;
  final bool? resizeToAvoidBottomInset;
  final bool Function()? canPop;
  final Widget Function(Object? error)? errorBuilder;
  final Widget Function()? emptyBuilder;
  final Widget Function()? loadingBuilder;
  final Widget Function()? noNetworkBuilder;
  final void Function(T controller)? clickEmptyOrError;
  final Future Function(T controller)? initMethod;
  final bool? isShowLoading;
  final Function(bool canPop)? onPop;
  final Widget Function(T controller)? bodyTopViewBuilder;
  final Widget Function(T controller)? bodyBottomViewBuilder;
  final bool useScaffold;
  final bool isCoverBodyTop;
  final double isCoverBodyTopPadding;
  final Widget? endDrawer;
  final Widget? drawer;

  const BaseGetBuilder({
    super.key,
    this.autoRemove = true,
    this.id,
    this.tag,
    this.builder,
    this.initMethod,
    this.global = true,
    this.assignId = false,
    this.filter,
    this.initState,
    this.dispose,
    this.didChangeDependencies,
    this.didUpdateWidget,
    this.init,
    this.backgroundView,
    this.appBar,
    this.backgroundColor,
    this.canPop,
    this.errorBuilder,
    this.emptyBuilder,
    this.clickEmptyOrError,
    this.noNetworkBuilder,
    this.loadingBuilder,
    this.isShowLoading = true,
    this.extendBodyBehindAppBar = false,
    this.resizeToAvoidBottomInset,
    this.onPop,
    this.bodyTopViewBuilder,
    this.bodyBottomViewBuilder,
    this.useScaffold = true,
    this.isCoverBodyTop = false,
    this.isCoverBodyTopPadding = 0,
    this.drawer,
    this.endDrawer,
  });

  T? get controller =>
      init ?? (Get.isRegistered<T>(tag: tag) ? Get.find<T>(tag: tag) : null);

  void doInitState() {
    clog("====> ${runtimeType.toString()} initState");
    if (initMethod != null) {
      try {
        controller?.executeInitMethod(() => initMethod!.call(controller!));
      } catch (e) {
        throw UnimplementedError(e.toString());
      }
    }
  }

  void doDispose() {
    clog("====> ${runtimeType.toString()} dispose");
  }

  @override
  Widget build(BuildContext context) {
    clog("====> ${runtimeType.toString()} build");
    Widget content = GetBuilder<T>(
      id: id,
      tag: tag,
      autoRemove: autoRemove,
      init: init,
      global: global,
      assignId: assignId,
      filter: filter,
      dispose: (GetBuilderState<T> state) {
        dispose?.call(state);
        doDispose();
      },
      didChangeDependencies: didChangeDependencies,
      didUpdateWidget: didUpdateWidget,
      initState: (GetBuilderState<T> state) {
        initState?.call(state);
        doInitState();
      },
      builder: (c) {
        Widget buildContent = useScaffold
            ? Scaffold(
                extendBodyBehindAppBar: extendBodyBehindAppBar,
                resizeToAvoidBottomInset: resizeToAvoidBottomInset,
                drawer: drawer,
                endDrawer: endDrawer,
                appBar: appBar,
                body: Column(
                  children: [
                    isCoverBodyTop == true
                        ? Expanded(
                            child: Stack(
                            children: [
                              Positioned.fill(
                                  top: isCoverBodyTopPadding,
                                  child: createBuilder(c)),
                              Positioned(
                                  top: 0,
                                  left: 0,
                                  right: 0,
                                  child: _getBuildBodyTopView(c))
                            ],
                          ))
                        : Expanded(
                            child: Column(
                            children: [
                              _getBuildBodyTopView(c),
                              Expanded(child: createBuilder(c))
                            ],
                          )),
                    _getBuildBodyBottomView(c)
                  ],
                ),
                backgroundColor: backgroundView != null &&
                        c.viewStatus != ViewStatus.noNetwork
                    ? Colors.transparent
                    : (backgroundColor ?? AppColor.colorF5F7FA),
              )
            : Container(
                color: backgroundView != null &&
                        c.viewStatus != ViewStatus.noNetwork
                    ? Colors.transparent
                    : (backgroundColor ?? AppColor.color181818),
                child: Column(
                  children: [
                    _getBuildBodyTopView(c),
                    Expanded(child: createBuilder(c)),
                    _getBuildBodyBottomView(c)
                  ],
                ),
              );
        if (backgroundView != null && c.viewStatus != ViewStatus.noNetwork) {
          buildContent = Stack(
            children: [
              if (backgroundColor != null)
                Positioned.fill(child: Container(color: backgroundColor)),
              backgroundView!,
              Positioned.fill(child: buildContent),
            ],
          );
        }
        return buildContent;
      },
    );
    return PopScope(
      canPop: canPop == null ? getCanPop() : canPop!(),
      onPopInvoked: onPopInvoked,
      child: content,
    );
  }

  Widget createBuilder(T c) {
    if (isShowLoading == false) {
      return buildTopLevelContent(c);
    } else if (c.viewStatus == ViewStatus.loading) {
      return loadingBuilder == null ? buildLoading() : loadingBuilder!.call();
    } else if (c.viewStatus == ViewStatus.empty) {
      return emptyBuilder == null ? buildEmpty() : emptyBuilder!.call();
    } else if (c.viewStatus == ViewStatus.error) {
      return errorBuilder == null ? buildError() : errorBuilder!.call(null);
    } else if (c.viewStatus == ViewStatus.noNetwork) {
      return noNetworkBuilder == null
          ? buildNoNetwork()
          : noNetworkBuilder!.call();
    } else {
      return buildTopLevelContent(c);
    }
  }

  Widget _getBuildBodyTopView(T controller) {
    return bodyTopViewBuilder == null
        ? buildBodyTopView(controller)
        : bodyTopViewBuilder!.call(controller);
  }

  Widget _getBuildBodyBottomView(T controller) {
    return bodyBottomViewBuilder == null
        ? buildBodyBottomView(controller)
        : bodyBottomViewBuilder!.call(controller);
  }

  Widget buildBodyTopView(T controller) {
    return const SizedBox();
  }

  Widget buildBodyBottomView(T controller) {
    return const SizedBox();
  }

  Widget buildTopLevelContent(T controller) {
    return builder == null
        ? buildContent(controller)
        : builder!.call(controller);
  }

  bool getCanPop() {
    return true;
  }

  void onPopInvoked(bool val) {
    onPop?.call(val);
  }

  Widget buildContent(T controller) {
    // TODO: implement buildContent
    throw UnimplementedError("buildContent 必须实现");
  }

  @override
  void clickToRefresh() {
    if (clickEmptyOrError != null) {
      clickEmptyOrError?.call(controller!);
    }
  }

  String? get statisticsAlias => null;

  // controller 已经 init, 未被 close 判断
  bool? get controllerIsRegistered => GetInstance().isRegistered<T>(tag: tag);
}
